/*****************************************************************************
 * Copyright (C) Stacy Curl. All rights reserved.                            *
 * ------------------------------------------------------------------------- *
 * The software in this package is published under the terms of the BSD      *
 * style license a copy of which has been included with this distribution in *
 * the LICENSE.txt file.                                                     *
 *****************************************************************************/
package picounit.features.registry;

import picounit.Registry;

import java.util.LinkedList;
import java.util.List;

public class RegistryEntries implements Registry, RegistryEntry {
	private final List<RegistryEntry> entries = new LinkedList<RegistryEntry>();
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	// Registry methods
	///////////////////////////////////////////////////////////////////////////////////////////////

	public <B, D extends B> void register(Class<B> type, Class<D> implementation) {
		addEntry(new InterfaceToImplementationRegistryEntry<B, D>(type, implementation));
	}

	public <B, D extends B> void register(Class<B> type, D instance) {
		addEntry(new InstanceRegistryEntry<B, D>(type, instance));
	}

	public void register(Class<?> implementation) {
		addEntry(new ImplementationRegistryEntry(implementation));
	}
	
	public void register(String key, boolean value) {
		addEntry(new BooleanRegistryEntry(key, value));
	}

	public void register(String key, byte value) {
		addEntry(new ByteRegistryEntry(key, value));
	}
	
	public void register(String key, char value) {
		addEntry(new CharacterRegistryEntry(key, value));
	}
	
	public void register(String key, double value) {
		addEntry(new DoubleRegistryEntry(key, value));
	}
	
	public void register(String key, float value) {
		addEntry(new FloatRegistryEntry(key, value));
	}
	
	public void register(String key, int value) {
		addEntry(new IntegerRegistryEntry(key, value));
	}
	
	public void register(String key, long value) {
		addEntry(new LongRegistryEntry(key, value));
	}
	
	public void register(String key, short value) {
		addEntry(new ShortRegistryEntry(key, value));
	}

	public void register(String key, String value) {
		addEntry(new StringRegistryEntry(key, value));
	}
	
	public <B> ImplementationCapturer<B> registerFactory(Class<B> type) {
		return new RegistryEntryImplementationCapturer<B> (type, this);
	}

	///////////////////////////////////////////////////////////////////////////////////////////////
	// RegistryEntry methods
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	public void registerWith(Registry registry) {
		for (RegistryEntry registryEntry : entries) {
			registryEntry.registerWith(registry);
		}
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	// Implementation methods
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	private void addEntry(RegistryEntry entry) {
		entries.add(entry);
	}

	public static class RegistryEntryImplementationCapturer<B> implements ImplementationCapturer<B> {
		private final Class<B> baseClass;
		private final RegistryEntries registryEntries;
		private final List<Object> implementationsAndInstances = new LinkedList<Object>();

		public RegistryEntryImplementationCapturer(Class<B> baseClass, RegistryEntries registryEntries) {
			this.baseClass = baseClass;
			this.registryEntries = registryEntries;
		}

		public <D extends B> ImplementationCapturer<B> add(Class<D> implementation) {
			return this;
		}

		public <D extends B> ImplementationCapturer<B> add(D instance) {
			return this;
		}

		public void done() {
			registryEntries.addEntry(new FactoryRegistryEntry<B>(baseClass, implementationsAndInstances));
		}
	}
}
